home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Celestin Apprentice 5
/
Apprentice-Release5.iso
/
Source Code
/
C
/
Snippets
/
Stuart's Tech Notes
/
Blobby password entry.c
< prev
next >
Wrap
Text File
|
1996-04-28
|
6KB
|
191 lines
// (C) 1992-1995 Stuart Cheshire <cheshire@cs.stanford.edu>
//
// This is password entry dialog box code, with a special custom FilterProc to
// do the 'blobby' password field because Apple provides no standard dialog item
// to give that behaviour. More re-inventing the wheel. It also checks whether
// any of the password is typed with Caps Lock pressed -- so that the user can
// be given a hint about the probable reason if their password is rejected.
#define USERNAME_RESOURCE_ID 128
#define CAPS_LOCK 0x39
// Dialogs in program
enum { dialog_password = 128 };
// Items in the password dialog
enum { dlog_OK = 1, dlog_Cancel, dlog_useritem, dlog_username, dlog_password };
typedef struct
{
Str255 user, pass;
Boolean EnableOK;
Boolean OutlineOK;
Boolean OldOutlineOK;
Boolean caps_pressed;
} PromptInfo;
local pascal void doOutlineOK(DialogPtr dlog, short item)
{
PromptInfo *info = (PromptInfo *)GetWRefCon(dlog);
int i;
short di_type;
Handle di_handle;
Rect di_box;
GetDItem(dlog, dlog_OK, &di_type, &di_handle, &di_box);
InsetRect(&di_box,-4,-4);
PenNormal();
PenSize(3,3);
if (!info->OutlineOK) ForeColor(whiteColor);
FrameRoundRect(&di_box,16,16);
PenNormal();
ForeColor(blackColor);
info->OldOutlineOK = info->OutlineOK;
}
static Boolean ClickButton(DialogPtr dlog, EventRecord *event, short *itemHit, short item)
{
short di_type;
ControlHandle di_handle;
Rect di_box;
GetDItem(dlog, item, &di_type, (Handle*)&di_handle, &di_box);
// If button not disabled, click it
if (di_handle[0]->contrlHilite != 255)
{
long finalTick;
HiliteControl(di_handle, inButton);
Delay(5, &finalTick);
HiliteControl(di_handle, 0);
*itemHit = item;
return(true);
}
else // else, ignore the event
{
event->what = nullEvent;
return(false);
}
}
static void DeleteRange(unsigned char *buffer, short start, short end)
{
unsigned char *last = buffer + buffer[0];
unsigned char *src = buffer + 1 + end;
unsigned char *dest = buffer + 1 + start;
while (src <= last) *dest++ = *src++; // Close up gap in string
buffer[0] -= (end-start); // Adjust the buffer's length
}
static void InsertChar(unsigned char *buffer, short pos, char c)
{
register short i = buffer[0];
if (i == 0xFF) return; // return if string already full
while (i > pos) { buffer[i+1] = buffer[i]; i--; }
buffer[pos+1] = c; // Fill in the new character
buffer[0]++; // Add one to the length of the string
}
static pascal Boolean FilterProc(DialogPtr dlog, EventRecord *event, short *itemHit)
{
PromptInfo *info = (PromptInfo *)GetWRefCon(dlog);
char key = event->message & charCodeMask;
Boolean editing_password = (((DialogPeek)dlog)->editField == dlog_password-1);
info->OutlineOK = info->EnableOK && (editing_password || info->pass[0]);
if (info->OldOutlineOK != info->OutlineOK) doOutlineOK(dlog, 1);
// Only do special processing for keyboard events
if (event->what != keyDown && event->what != autoKey) return(false);
// if in password field, or if password field is already filled in, Return & Enter
// are equivalent to hitting the OK button
// Otherwise they are equivalent to a TAB, to move us into the password field.
// This is because Unix users often press return after entering their user name
// instead of TAB -- no need to make there lives any harder.
if (key==3 || key==13)
{
// If OK button is outlined, then pressing <Return> hits it
if (info->OutlineOK) return(ClickButton(dlog, event, itemHit, 1));
else { event->message = '\t'; return(false); }
}
// Escape or Command-Period hits cancel
if (key==27 || (key == '.' && event->modifiers & cmdKey))
return(ClickButton(dlog, event, itemHit, 2));
// Ignore command keys
if (event->modifiers & cmdKey) { event->what = nullEvent; return(false); }
// All keys except Tab and cursor keys get our special treatment
if (editing_password && key!='\t' && (key<28 || key>31))
{
short start = (*((DialogPeek)dlog)->textH)->selStart; // Get current selection
short end = (*((DialogPeek)dlog)->textH)->selEnd;
if (start > info->pass[0]) start = info->pass[0]; // Sanity checks,
if (end > info->pass[0]) end = info->pass[0]; // just in case
if (start != end) DeleteRange(info->pass,start,end); // If there's a selection, delete it
// If not delete key then stash the key and change code to a blob, else
// see if we have to delete a single character (when there is no selection)
if (key != 8)
{
unsigned char km[16];
GetKeys((unsigned long *)km);
if (km[CAPS_LOCK>>3] & 1 << (CAPS_LOCK & 7)) info->caps_pressed = TRUE;
InsertChar(info->pass,start,key);
event->message = '•';
}
else if (start == end && start > 0) DeleteRange(info->pass,start-1,start);
}
return(false); // Let ModalDialog insert the fake char
}
static void do_dialog(void)
{
Handle username = GetResource('STR ', USERNAME_RESOURCE_ID);
PromptInfo info;
short di_type, item;
Handle di_handle;
Rect di_box;
DialogPtr modal = GetNewDialog(dialog_password, NULL, (WindowPtr)(-1));
GetDItem(modal, dlog_useritem, &di_type, &di_handle, &di_box);
SetDItem(modal, dlog_useritem, di_type, (Handle)doOutlineOK, &di_box);
GetDItem(modal, dlog_username, &di_type, &di_handle, &di_box);
SetIText(di_handle, (StringPtr)*username); // Get username from resource
GetIText(di_handle, info.user); // and initialize 'user' with it.
SelIText(modal, dlog_username, 0, 32767);
info.pass[0] = 0;
info.EnableOK = (info.user[0] > 0);
info.OutlineOK = info.OldOutlineOK = info.caps_pressed = FALSE;
SetWRefCon(modal,(long)&info);
ShowWindow(modal);
while(TRUE)
{
SetPort(modal);
GetDItem(modal, dlog_OK, &di_type, &di_handle, &di_box);
HiliteControl((ControlHandle)di_handle, info.EnableOK ? 0 : 255);
ModalDialog(FilterProc, &item);
GetDItem(modal, dlog_username, &di_type, &di_handle, &di_box);
GetIText(di_handle, info.user);
info.EnableOK = (info.user[0] > 0);
if (item == dlog_Cancel) break;
else if (item == dlog_OK)
{
// do required stuff with (info.user, info.pass);
// if password is bad, and info.caps_pressed is TRUE,
// maybe warn the user and try again?
break;
}
}
ReleaseResource(username);
DisposDialog(modal);
}